/*
文件指针 FILE
文件打开 fopen
        FILE *fp=NULL;//文件类型指针
        fp=fopen("文件路径","打开方式");
            文件路径：可以是相对路径，相对于当前的路径   绝对路径：在linux ,以根目录为起点 在windows下以盘符为起点
            打开方式：r :只读的方式  w：只写的方式    a：追加的方式   +:可读可写 ，该符号与r/w/a叠加使用
                    r:如果文件不存在，会打开失败，有内容不会删除
                    w：如果文件不存在，会新建文件，如果文件存在,内容会清空
                    r+:如果文件不存在，会打开失败，有内容不会删除
                    w+:如果文件不存在，会新建文件，如果文件存在,内容会清空  如果想读数据 只能先写然后移动文件读写位置 再读
                    a:如果文件不存在，会新建，存在的话内容不会清空,文件读写操作停留在文件的末尾  不能写，只能读
                    a+：可读可写  读从文件开头开始读 写在文件末尾写
文件关闭
        fclose(文件指针);
文件读写操作：
                         读           写
            字符读写    fgetc   和   fputc
            字符串读写  fgets   和   fputs   
              fgets(str,n,fp);//从文件中读n-1个字节到字符数组str  ，当数据不足n-1个时，遇到回车/换行/结束符停止,如果遇到换行会将回车读走
            格式化读写  fscanf  和   fprintf
            用法与scanf和printf函数非常像，不同的是前面多了一个文件指针的参数  fsacnf函数遇到空格/回车/tab停止读取 遇到回车结束
        二进制/模块化读写fwrite  和  fread
文件读写位置移动函数
    fseek(文件指针，移动字节数，移动起始位置)；
            移动字节数：3L :往后移动3个字节    ；-3L/3：往前移动3个字节
            移动位置：SEEK_END(2) :文件末尾     SEEK_SET(0) ：文件开头    SEEK_CUR(1)：文件当前位置  
    rewind(文件指针)；//将文件读写指针一直文件首位置
文件末尾符号 ：EOF  
        判断是否读到文件末尾的函数 : feof(fp)  如果到了文件末尾 会返回真，否则返回假


*/
#include <stdio.h>
#include <string.h>
void file_r(void)
{
    FILE *fp;
    //当前路径下的1.txt  相对路径
    fp=fopen("1.txt","r");//以只读的方式打开1.txt文件
    if(fp==NULL)//文件打开失败
    {
        printf("文件r方式打开失败\n");
        return ;
    }
    printf("文件r方式打开成功\n");
    //通过fgetc读取一个字符
    char ch;
    ch=fgetc(fp);
  
    putchar(ch);//输出读到字符
    putchar('\n');//换行
      //向文件写入一个字符  通过fputc函数
      fputc('y',fp);//这个y是无法写入  因为当前文件的打开方式为只读
    //关闭文件
    fclose(fp);//
}
void file_w(void)
{
    FILE *fp;
      //以只写的方式打开1.txt
      fp=fopen("1.txt","w");//以只写的方式打开
      if(fp==NULL)
      {
          printf("文件w方式打开失败\n");
          return ;
      } 
      else
     {
        printf("文件w打开成功\n");
    //通过fgetc读取一个字符
    char ch;
    ch=fgetc(fp);
    putchar(ch);//输出读到字符

    putchar('\n');//换行
      //关闭文件
      fclose(fp);//
     }
}
void file_r_add(void)
{
    FILE *fp;
    fp=fopen("1.txt","r+");//以可读可写的方式打开  有内容的情况下
    if(fp==NULL)
    {
        printf("文件r+方式打开失败\n");
        return ;
    } 
    printf("文件r+打开成功\n");
       //通过fgetc读取一个字符
       char ch;
       ch=fgetc(fp);
       putchar(ch);//输出读到字符
       ch=fgetc(fp);
       putchar(ch);//输出读到字符
       putchar('\n');//换行
       //向文件写入一个字符  通过fputc函数
       fputc('v',fp);
    //关闭文件
    fclose(fp);//
}
void file_w_add(void)
{
    FILE *fp;

    fp=fopen("1.txt","w+");//以可读可写的方式打开  有内容的情况下
    if(fp==NULL)
    {
        printf("文件w+方式打开失败\n");
        return ;
    } 
    printf("文件w+打开成功\n");
     //通过fgetc读取一个字符
     char ch;
     ch=fgetc(fp);
     putchar(ch);//输出读到字符
     putchar('\n');//换行
    //关闭文件
    fclose(fp);//
}
void file_add(void)
{
    FILE *fp;
    //fp=fopen("2.txt","a");//以追加的方式打开  有内容的情况下
    fp=fopen("2.txt","a+");//以追加的方式可读可写打开  
    if(fp==NULL)
    {
        printf("文件a方式打开失败\n");
        return ;
    } 
    printf("文件a打开成功\n");
     //通过fgetc读取一个字符
     char ch;
     ch=fgetc(fp);
     putchar(ch);//输出读到字符
     putchar('\n');//换行
       //向文件写入一个字符  通过fputc函数
       fputc('z',fp);//
    //关闭文件
    fclose(fp);//
}
//以绝对路径方式打开文件
void file_path2(void)
{
    FILE *  fp  =NULL;
    fp=fopen("/home/linux/test/FILE/3.txt","r");//绝对路径 以只读的方式打开2.txt
    if(fp)
    {
        printf("绝对类路径方式文件打开成功\n");
    } 
    else
    {
        printf("绝对类路径方式文件打开失败\n");
        return ;
    }
    fclose(fp);
}
//文件位置移动
void file_position(void)
{
    FILE *fp=NULL;//文件指针
    fp=fopen("3.txt","w+");//以可读可写方式打开3.txt文件
    if(NULL==fp)
    {
        printf("文件打开失败\n");
        return ;
    }
    //向3.txt文件写入一串字符
    char str[100]={"hello world"};
    //fputc将内容写入文件  一次只能写入一个字节
    int i=0;
    while(str[i])
    {
        fputc(str[i],fp);
        i++;//往后继续写入
    }
    printf("i=%d\n",i);
    //通过文件读写位置函数移动 “光标”
    //rewind(fp);//将位置移到文件首位置（开头）
    fseek(fp,0,SEEK_SET);
    //将文件中的数据读入 buf
    char buf[100]={'\0'};
    i=0;
    while(1)
    {
        if(feof(fp))//判断是否到了文件末尾 
        {
            break;//结束循环
        }
        buf[i]=fgetc(fp);//从文件中读一个字符
        i++;//将读到数据存入下一个元素
    }
    buf[i-1]='\0';
    printf("i=%d,buf:%s,%lu\n",i,buf,strlen(buf));
    printf("%d\n",buf[i-1]);
    //关闭文件
    fclose(fp);
}
void file_fgets_fputs(void)
{
    FILE *fp=NULL;//文件指针
    fp=fopen("fgets_fputs.txt","a+");//r+：从文件首位置开始写入会覆盖前面的内容  w+  :刷新写入  a+:追加写入
    if(NULL==fp)
    {
        printf("文件打开失败\n");
        return ;
    }
    char str[100]={"8888\n"};
    fputs(str,fp);//写入一串字符
    fputs(str,fp);
    //将读写位置移动 移到文件首位置  
    rewind(fp);
    char buf[100]={'\0'};
    fgets(buf,sizeof(buf),fp);//从文件中读取sizeof(buf)-1个字符存入str  遇到换行停止读取
    printf("buf:%s\n",buf);
    fclose(fp);
}
//格式化读写操作
void file_fscanf_fprintf(void)
{
    struct file1
    {
       char name[20];
       int age;
       double score;
    }a={"zhangsan",19,98.7};//声明一个结构体类型并定义一个变量a并初始化赋值
    struct file1 b,c;//定义结构体类型变量
    FILE *fp=NULL;//文件指针
    fp=fopen("fscanf_fprintf.txt","w+");//打开文件
    if(NULL==fp)
    {
        return;
    }
    //a的信息输出到终端（屏幕）
    printf("%s %d %.2lf\n",a.name,a.age,a.score);
    //将a的信息  输出到文件
    fprintf(fp,"%s %d %.2lf\n",a.name,a.age,a.score);
    //通过键盘输入数据到b
    scanf("%s%d%lf",b.name,&b.age,&b.score);//输入的时候也要按照格式要求加入逗号 数据才会正确
    printf("b的信息：%s,%d,%.2lf\n",b.name,b.age,b.score);
    //从文件中通过fscanf函数将数据读取出来  存入变量c
    rewind(fp);//移到文件首位置
    fscanf(fp,"%s%d%lf",c.name,&c.age,&c.score);//遇到空格/回车/tab停止读取 
    printf("c的信息：%s,%d,%.2lf\n",c.name,c.age,c.score);
    fclose(fp);//关闭文件
}

//模块化读写
void file_fwrite_fread(void)
{
    struct file1
    {
       char name[20];
       int age;
       double score;
    }a={"zhangsan",19,98.7};//声明一个结构体类型并定义一个变量a并初始化赋值
    struct file1 b,c;//定义结构体类型变量
    FILE *fp=NULL;//文件指针
    fp=fopen("fwrite_fread.txt","w+");//打开文件
    if(NULL==fp)
    {
        return;
    }
    //将a的书通过fwrite写入文件
    fwrite(&a,sizeof(struct file1),1,fp);//参数（写入的数据地址，写入内容的大小，几块（内容大小），文件指针）
    //将数据从文件中通过fread读取出来
    rewind(fp);
    fread(&b,sizeof(struct file1),1,fp);
    printf("b的信息：%s,%d,%.2lf\n",b.name,b.age,b.score);
    fclose(fp);
    //2.写入结构体数组
    struct file1 num[2]={{"lisisan",39,78.7},{"wangwuliu",20,88.7}},arr[2];
    FILE *stu_fp=fopen("stu.txt","w+");
    if(!stu_fp)//等价于 fp==NULL
    {
        printf("文件打开失败\n");
        return;
    }
    //方法1  循环写入----
    // for(int i=0;i<2;i++)
    // {
    //     fwrite(&num[i],sizeof(struct file1),1,stu_fp);
    // }
    //=================================
    //方法2  一次性写入
    fwrite(num,sizeof(struct file1),2,stu_fp);
    //将文件读写位置移动
    rewind(stu_fp);
    //方法1：循环读出
    // for(int i=0;i<2;i++)
    // {
    //     fread(&arr[i],sizeof(struct file1),1,stu_fp);
    // }
     //=================================
    //方法2  一次性读出
    fread(arr,sizeof(struct file1),2,stu_fp);

    fclose(stu_fp);
    printf("输出读取的信息");
    //输出arr的信息
    for(int i=0;i<2;i++)
    {
        printf("%s,%d,%.2lf\n",arr[i].name,arr[i].age,arr[i].score);
    }


   
}
int main(int argc, char const *argv[])
{
    file_fwrite_fread();
    //file_fscanf_fprintf();
   // file_fgets_fputs();
 // file_r();
   // file_w();//为什么不管是w还是w+都读不到数据  是因为 一开始打开文件 内容已清空 所以读不到 除非先写 再移动文件读写位置再读才可以（仅限于w+方式）
//   file_r_add();
//  file_w_add();
  //file_add();
// file_path2();
// file_position();
    return 0;
}
